﻿using System;
using System.Linq;
using Ibp.Service.Entity.ODAEntity;
using OdaOperation.Core.Parameters;
using OdaOperation.Core.Parameters.Base;
using OdaOperation.Extends;
using OdaOperation.Model;
using Teigha.Core;
using Teigha.TD;

namespace OdaOperation.Core.Creators
{
    /// <summary>
    /// 表格创建器类，继承了BaseCreator类，
    /// 并实现了ICreate<TableCreator>、IReferenceCreator和ISetParameter<TableCreator, TableParameter>接口。
    /// </summary>
    public class TableCreator : BaseCreator, ICreate<TableCreator>, IReferenceCreator, ISetParameter<TableCreator, TableParameter>
    {
        /// <summary>
        /// 表格参数对象
        /// </summary>
        private TableParameter m_parameter;

        /// <summary>
        /// 表格创建器的构造函数，接收一个数据库对象作为参数
        /// </summary>
        /// <param name="pDb"></param>
        public TableCreator(OdDbDatabase pDb)
            : base(pDb) // 调用基类(BaseCreator)的构造函数
        {
        }

        /// <summary>
        ///  创建一个块引用的方法，接收位置、缩放、旋转和镜像平面等参数
        /// </summary>
        /// <param name="location"></param>
        /// <param name="odGeScale"></param>
        /// <param name="rotating"></param>
        /// <param name="mirrorPlane"></param>
        public void CreateBlockReference(DPoint location, OdGeScale3d odGeScale = null, double rotating = 0.0, OdGePlane mirrorPlane = null)
        {
            // 调用BlockReferenceCreator类的Create方法创建块引用
            new BlockReferenceCreator(m_database, m_parameter.BlockName, m_layerName).Create(new OdGePoint3d(location.X, location.Y, location.Z), odGeScale, rotating, mirrorPlane);
        }

        /// <summary>
        ///  创建一个块引用的方法，接收位置、缩放、旋转和镜像平面等参数
        /// </summary>
        /// <param name="location"></param>
        /// <param name="odGeScale"></param>
        /// <param name="rotating"></param>
        /// <param name="mirrorPlane"></param>
        public void CreateBlockReference(OdGePoint3d location, OdGeScale3d odGeScale = null, double rotating = 0.0, OdGePlane mirrorPlane = null)
        {
            // 调用BlockReferenceCreator类的Create方法创建块引用
            new BlockReferenceCreator(m_database, m_parameter.BlockName, m_layerName).Create(location, odGeScale, rotating, mirrorPlane);
        }

        /// <summary>
        /// 创建一个块引用的方法，接收图层名称、位置、缩放、旋转、镜像平面和参数集等参数
        /// </summary>
        /// <param name="layerName"></param>
        /// <param name="location"></param>
        /// <param name="odGeScale"></param>
        /// <param name="rotating"></param>
        /// <param name="mirrorPlane"></param>
        /// <param name="paramters"></param>
        public void CreateBlockReference(string layerName, DPoint location, OdGeScale3d odGeScale = null, double rotating = 0.0, OdGePlane mirrorPlane = null, ParameterSet paramters = null)
        {
            // 调用BlockReferenceCreator类的Create方法创建块引用
            new BlockReferenceCreator(m_database, m_parameter.BlockName, layerName).Create(location.ToGePoint3D(), odGeScale, rotating, mirrorPlane);
        }

        /// <summary>
        /// 创建一个块引用的方法，接收参考参数
        /// </summary>
        /// <param name="paramter"></param>
        public void CreateBlockReference(ReferenceParameter paramter)
        {
            // 调用BlockReferenceCreator类的Create方法创建块引用
            new BlockReferenceCreator(m_database, m_parameter.BlockName, paramter.LayerName).Create(paramter.Location.ToGePoint3D(), paramter.Scale, paramter.Rotating, paramter.MirrorPlane, paramter.Parameters);
        }

        /// <summary>
        /// 创建表格
        /// </summary>
        /// <returns></returns>
        public TableCreator Create()
        {
            m_parameter.Check(); // 检查参数的有效性
            m_parameter.TableSize.InitFromTable(m_parameter.TableData); // 从表格数据中初始化表格大小
            OdDbObjectId font = TextStyleCreator.GetFont(m_database, m_parameter.FontStyle); // 获取字体对象
            OdDbBlockTable odDbBlockTable = m_database.getBlockTableId().openObject() as OdDbBlockTable; // 获取块表对象

            // 计算表格的宽度和高度
            TableSize tableSize = m_parameter.TableSize;
            double width = m_parameter.TableSize.Cols.Sum();
            double yy = m_parameter.TableSize.Rows.Sum();

            OdGePoint3d odGePoint3d = new OdGePoint3d(0.0, yy, 0.0); // 表格左上角的点
            OdGeVector3d xAxis = new OdGeVector3d(1.0, 0.0, 0.0); // X轴方向向量
            OdGeVector3d yAxis = new OdGeVector3d(0.0, -1.0, 0.0); // Y轴方向向量

            OdDbBlockTableRecord odDbBlockTableRecord; // 块表记录对象

            if (odDbBlockTable.has(m_parameter.BlockName))
            {
                // 如果块表中已存在指定名称的记录
                odDbBlockTableRecord = odDbBlockTable.getAt(m_parameter.BlockName, OpenMode.kForWrite) as OdDbBlockTableRecord;
            }
            else
            {
                // 如果块表中不存在指定名称的记录
                odDbBlockTableRecord = OdDbBlockTableRecord.createObject();
                odDbBlockTableRecord.setName(m_parameter.BlockName);
                odDbBlockTable.upgradeOpen();
                odDbBlockTable.add(odDbBlockTableRecord);
                odDbBlockTable.downgradeOpen();
            }

            m_blockTableId = odDbBlockTableRecord.objectId(); // 设置块表ID

            // 创建表格项创建器和网格创建器
            TableItemCreator tableItemCreate = new TableItemCreator(m_database, m_blockTableId, m_layerName, font, odGePoint3d, xAxis, yAxis, m_parameter.FontSize);
            GridCreator gridCreator = new GridCreator(m_database, m_blockTableId, m_layerName);

            if (m_parameter.TableSize.Rows.Count == m_parameter.TableData.Count && m_parameter.TableSize.Cols.Count == m_parameter.TableData.Max((TableRow x) => x.Count))
            {
                // 如果表格行数等于表格数据行数，并且表格列数等于表格数据最大列数
                gridCreator.CreateGrid(m_parameter.TableSize, odGePoint3d, xAxis, yAxis); // 创建网格
                CreateTableData(font, width, odGePoint3d, xAxis, yAxis, odDbBlockTableRecord, tableItemCreate); // 创建表格数据
            }
            else
            {
                // 如果表格行数和列数不符合要求
                gridCreator.CreateGrid(m_parameter.TableSize, m_parameter.TableData, odGePoint3d, xAxis, yAxis); // 创建网格
                CreateMixTableData(font, width, odGePoint3d, xAxis, yAxis, odDbBlockTableRecord, tableItemCreate); // 创建混合表格数据
            }

            return this; // 返回当前对象
        }

        /// <summary>
        /// 创建混合表格数据
        /// </summary>
        /// <param name="textStyle"></param>
        /// <param name="width"></param>
        /// <param name="location"></param>
        /// <param name="xAxis"></param>
        /// <param name="yAxis"></param>
        /// <param name="blockTableRecord"></param>
        /// <param name="tableItemCreate"></param>
        /// <exception cref="ArgumentNullException"></exception>
        private void CreateMixTableData(OdDbObjectId textStyle, double width, OdGePoint3d location, OdGeVector3d xAxis, OdGeVector3d yAxis, OdDbBlockTableRecord blockTableRecord, TableItemCreator tableItemCreate)
        {
            // 如果存在标题
            if (m_parameter.Title != null)
            {
                // 创建标题
                OdDbText odDbText = OdDbText.createObject();
                odDbText.setTextString(m_parameter.Title.Title);
                OdGeExtents3d odGeExtents3d = new OdGeExtents3d();

                if (textStyle != null)
                {
                    odDbText.setTextStyle(textStyle);
                }

                odDbText.setHeight(m_parameter.Title.Size);
                odDbText.setDatabaseDefaults(m_database);
                blockTableRecord.appendOdDbEntity(odDbText);
                odDbText.getGeomExtents(odGeExtents3d);
                double num = odGeExtents3d.maxPoint().y - odGeExtents3d.minPoint().y;
                double num2 = odGeExtents3d.maxPoint().x - odGeExtents3d.minPoint().x;
                OdGePoint3d odGePoint3d = new OdGePoint3d(location).Add(new OdGeVector3d(xAxis).Mul(width * 0.5 - num2 * 0.5).Add(new OdGeVector3d(yAxis).Mul(-10.0)));
                odDbText.setAlignmentPoint(odGePoint3d);
                odDbText.setPosition(odGePoint3d);
                odDbText.setLayer(m_layerName);
            }

            double num3 = 0.0;
            double num4 = 0.0;
            TableSize tableSize = m_parameter.TableSize;
            TableData tableData = m_parameter.TableData;

            for (int i = 0; i < tableSize.Rows.Count; i++)
            {
                num4 += tableSize.Rows[i];
                TableRow tableRow = tableData[i];
                int num5 = 0;

                foreach (TableItem item in tableRow)
                {
                    if (item == null)
                    {
                        throw new ArgumentNullException($"第{i}行， 第{num5}列 item 不能为空");
                    }

                    double num6 = 0.0;

                    for (int j = 0; j < item.LeftIndex; j++)
                    {
                        num6 += tableSize.Cols[j];
                    }

                    double num7 = num6;

                    for (int k = 0; k < item.ColSpan; k++)
                    {
                        num7 += tableSize.Cols[item.LeftIndex + k];
                    }

                    double num8 = num3;

                    for (int l = 0; l < item.RowSpan; l++)
                    {
                        num8 += tableSize.Rows[i + l];
                    }

                    num5 += item.ColSpan;
                    tableItemCreate.Create(item, num6, num7, num3, num8);
                }

                num3 = num4;
            }
        }

        /// <summary>
        /// 创建表格数据
        /// </summary>
        /// <param name="textStyle"></param>
        /// <param name="width"></param>
        /// <param name="location"></param>
        /// <param name="xAxis"></param>
        /// <param name="yAxis"></param>
        /// <param name="blockTableRecord"></param>
        /// <param name="tableItemCreate"></param>
        /// <exception cref="ArgumentNullException"></exception>
        private void CreateTableData(OdDbObjectId textStyle, double width, OdGePoint3d location, OdGeVector3d xAxis, OdGeVector3d yAxis, OdDbBlockTableRecord blockTableRecord, TableItemCreator tableItemCreate)
        {
            if (m_parameter.Title != null)
            {
                // 如果存在标题
                OdDbText odDbText = OdDbText.createObject();
                odDbText.setTextString(m_parameter.Title.Title);
                OdGeExtents3d odGeExtents3d = new OdGeExtents3d();

                if (textStyle != null)
                {
                    odDbText.setTextStyle(textStyle);
                }

                odDbText.setHeight(m_parameter.Title.Size);
                odDbText.setDatabaseDefaults(m_database);
                blockTableRecord.appendOdDbEntity(odDbText);
                odDbText.getGeomExtents(odGeExtents3d);
                double num = odGeExtents3d.maxPoint().y - odGeExtents3d.minPoint().y;
                double num2 = odGeExtents3d.maxPoint().x - odGeExtents3d.minPoint().x;
                OdGePoint3d odGePoint3d = new OdGePoint3d(location).Add(new OdGeVector3d(xAxis).Mul(width * 0.5 - num2 * 0.5).Add(new OdGeVector3d(yAxis).Mul(-10.0)));
                odDbText.setAlignmentPoint(odGePoint3d);
                odDbText.setPosition(odGePoint3d);
                odDbText.setLayer(m_layerName);
            }

            double top = 0.0;
            double num3 = 0.0;
            TableSize tableSize = m_parameter.TableSize;
            TableData tableData = m_parameter.TableData;

            for (int i = 0; i < tableSize.Rows.Count; i++)
            {
                num3 += tableSize.Rows[i];
                double left;
                double num4 = (left = 0.0);

                for (int j = 0; j < tableSize.Cols.Count; j++)
                {
                    num4 += tableSize.Cols[j];
                    TableItem item = tableData[i][j] ?? throw new ArgumentNullException($"第{i}行， 第{j}列 item 不能为空");
                    tableItemCreate.Create(item, left, num4, top, num3);
                    left = num4;
                }

                top = num3;
            }
        }

        /// <summary>
        /// 设置表格参数的方法
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public TableCreator SetParameter(TableParameter parameter)
        {
            parameter.Check(); // 检查参数的有效性
            m_parameter = parameter; // 设置参数对象
            m_layerName = parameter.LayerName; // 设置图层名称
            return this; // 返回当前对象
        }
    }

}